home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / grafica / amhelios / p_render.cpp < prev    next >
C/C++ Source or Header  |  1999-01-01  |  17KB  |  623 lines

  1. ////////////////////////////////////////////////////////////
  2. //
  3. //  P_RENDER.CPP - Polygon Renderer Class
  4. //
  5. //  Version:    1.03A
  6. //
  7. //  History:    94/08/23 - Version 1.00A release.
  8. //              94/11/26 - Added contrast and intensity
  9. //                         adjustment to GetVertexInfo.
  10. //                       - Added vertex color scaling and
  11. //                         clipping to GetVertexInfo.
  12. //                       - Modified Open function to
  13. //                         calculate color scaling factor.
  14. //              94/12/16 - Version 1.01A release.
  15. //              95/02/05 - Version 1.02A release.
  16. //              95/03/21 - Modified Render and GetVertexInfo
  17. //                         functions to accept subpixel
  18. //                         offsets for antialiasing.
  19. //              95/03/22 - Added Reset function.
  20. //              95/03/25 - Removed gamma correction and
  21. //                         color jittering from DrawEdgeList
  22. //                         function.
  23. //              95/06/05 - Modified DrawEdgeList and
  24. //                         ScanEdges functions to convert
  25. //                         pseudodepth to long data type.
  26. //                       - Added EdgeSetup, EdgeScan,
  27. //                         SpanSetup and SpanScan functions.
  28. //                       - Changed DrawEdgeList and
  29. //                         ScanEdges functions from floating
  30. //                         point to integer and long data
  31. //                         types for DDA caculations.
  32. //              95/06/30 - Modified SpanScan function to use
  33. //                         bitmap pixel functions.
  34. //              95/07/05 - Modified Render function to
  35. //                         accept supersampling rate
  36. //                         parameter and initialize ss_rate
  37. //                         data member.
  38. //                       - Modified GetVertexInfo, EdgeScan
  39. //                         and SpanScan to use supersampling
  40. //                         bitmap.
  41. //              95/07/21 - Version 1.02B release.
  42. //              96/02/14 - Version 1.02C release.
  43. //              96/04/01 - Version 1.03A release.
  44. //
  45. //  Compilers:  Microsoft Visual C/C++ Professional V1.5
  46. //              Borland C++ Version 4.5
  47. //
  48. //  Author:     Ian Ashdown, P.Eng.
  49. //              byHeart Software Limited
  50. //              620 Ballantree Road
  51. //              West Vancouver, B.C.
  52. //              Canada V7S 1W3
  53. //              Tel. (604) 922-6148
  54. //              Fax. (604) 987-7621
  55. //
  56. //  Copyright 1994-1996 byHeart Software Limited
  57. //
  58. //  The following source code has been derived from:
  59. //
  60. //    Ashdown, I. 1994. Radiosity: A Programmer's
  61. //    Perspective. New York, NY: John Wiley & Sons.
  62. //
  63. //  It may be freely copied, redistributed, and/or modified
  64. //  for personal use ONLY, as long as the copyright notice
  65. //  is included with all source code files.
  66. //
  67. ////////////////////////////////////////////////////////////
  68.  
  69. #include "p_render.h"
  70.  
  71. // Open polygon renderer
  72. BOOL PolyRender::Open( WinBitmap *pb, double rmax )
  73. {
  74.   int row, col;         // Loop indices
  75.  
  76.   // Calculate color scaling factor
  77.   CalcColorScale(rmax);
  78.  
  79.   pbmap = pb;   // Save bitmap object pointer
  80.  
  81.   height = pbmap->GetHeight();
  82.   width = pbmap->GetWidth();
  83.  
  84.   // Allocate edge list
  85.   if ((edge_list = new EdgeInfo[height]) == NULL)
  86.     return FALSE;
  87.  
  88.   // Allocate depth buffer
  89.   if ((z_buffer = new (long (*[height]))) != NULL)
  90.   {
  91.     for (row = 0; row < height; row++)
  92.     {
  93.       if ((z_buffer[row] = new long[width]) == NULL)
  94.       {
  95.         // Release partially allocated depth buffer
  96.         row--;
  97.         for ( ; row >= 0; row--)
  98.           delete [] z_buffer[row];
  99.         delete [] z_buffer;
  100.  
  101.         // Release edge list memory
  102.         delete [] edge_list;
  103.  
  104.         return FALSE;
  105.       }
  106.     }
  107.   }
  108.   else
  109.   {
  110.     delete [] edge_list;        // Release edge list memory
  111.     return FALSE;
  112.   }
  113.  
  114.   // Initialize depth buffer
  115.   for (row = 0; row < height; row++)
  116.     for (col = 0; col < width; col++)
  117.       z_buffer[row][col] = PR_Infinity;
  118.  
  119.   return TRUE;
  120. }
  121.  
  122. void PolyRender::Reset()        // Reset polygon renderer
  123. {
  124.   int row, col;         // Loop indices
  125.   ColorRGB rgb;         // Temporary color
  126.  
  127.   // Define background color
  128.   rgb.SetRed((BYTE) 0);
  129.   rgb.SetGreen((BYTE) 0);
  130.   rgb.SetBlue((BYTE) 0);
  131.  
  132.   for (row = 0; row < height; row++)
  133.     for (col = 0; col < width; col++)
  134.     {
  135.       // Clear bitmap pixel
  136.       pbmap->SetPixel(col, row, rgb);
  137.  
  138.       // Reinitialize depth buffer element
  139.       z_buffer[row][col] = PR_Infinity;
  140.     }
  141. }
  142.  
  143. void PolyRender::Close()        // Close polygon shader
  144. {
  145.   int row;      // Loop index
  146.  
  147.   delete [] edge_list;          // Release edge list memory
  148.  
  149.   // Delete depth buffer
  150.   for (row = 0; row < height; row++)
  151.     delete [] z_buffer[row];
  152.   delete [] z_buffer;
  153. }
  154.  
  155. // Render polygon
  156. void PolyRender::Render( OutPolygon &out, int rate, double
  157.     x_offset, double y_offset )
  158. {
  159.   ss_rate = rate;       // Initialize supersampling rate
  160.  
  161.   // Get vertex information
  162.   GetVertexInfo(out, x_offset, y_offset);
  163.  
  164.   ScanEdges();          // Scan convert edges
  165.   DrawEdgeList();       // Draw edge list
  166. }
  167.  
  168. // Get vertex information
  169. void PolyRender::GetVertexInfo( OutPolygon &out, double
  170.     x_offset, double y_offset )
  171. {
  172.   int i;                // Loop index
  173.   double emax;          // Maximum color band value
  174.   double u;             // u-axis coordinate
  175.   double v;             // v-axis coordinate
  176.   VertexInfo *pv;       // Vertex info element pointer
  177.   Point3 posn;          // Normalized vertex position
  178.  
  179.   // Initialize polygon y-axis limits
  180.   ymax = 0;
  181.   ymin = height - 1;
  182.   ss_ymax = 0;
  183.   ss_ymin = ymin * ss_rate;
  184.  
  185.   // Get number of vertices
  186.   num_vert = out.GetNumVert();
  187.  
  188.   for (i = 0; i < num_vert; i++)
  189.   {
  190.     pv = &(v_info[i]);  // Get vertex info element pointer
  191.  
  192.     // Get vertex normalized view space co-ordinates
  193.     posn = out.GetVertexPosn(i);
  194.  
  195.     // Scale and limit view space u-axis co-ordinate
  196.     u = posn.GetX() * (width + x_offset);
  197.     if (u > width)
  198.       u = width;
  199.     else if (u < 0.0)
  200.       u = 0.0;
  201.     pv->posn.SetX(u);
  202.  
  203.     // Scale and limit view space v-axis co-ordinate
  204.     v = posn.GetY() * (height + y_offset);
  205.     if (v > height)
  206.       v = height;
  207.     else if (v < 0.0)
  208.       v = 0.0;
  209.     pv->posn.SetY(v);
  210.  
  211.     // Get view space n-axis co-ordinate
  212.     pv->posn.SetZ(posn.GetZ());
  213.  
  214.     // Convert to supersampling screen space co-ordinates
  215.     //
  216.     // NOTE: top scan line and rightmost pixels are never
  217.     //       drawn, so there is no need to limit maximum
  218.     //       screen co-ordinates to (width - 1) and
  219.     //       (height - 1)
  220.     //
  221.     pv->ss_screen.x = (int) (pv->posn.GetX() * ss_rate);
  222.     pv->ss_screen.y = (int) (pv->posn.GetY() * ss_rate);
  223.  
  224.     // Convert to screen space co-ordinates (round up)
  225.     pv->screen.x = (pv->ss_screen.x + ss_rate - 1) / ss_rate;
  226.     pv->screen.y = (pv->ss_screen.y + ss_rate - 1) / ss_rate;
  227.  
  228.     // Update polygon y-axis limits
  229.     if (pv->screen.y < ymin)
  230.       ymin = pv->screen.y;
  231.     if (pv->ss_screen.y < ss_ymin)
  232.       ss_ymin = pv->ss_screen.y;
  233.  
  234.     if (pv->screen.y > ymax)
  235.       ymax = pv->screen.y;
  236.     if (pv->ss_screen.y > ss_ymax)
  237.       ss_ymax = pv->ss_screen.y;
  238.  
  239.     // Get vertex color
  240.     pv->color = out.GetVertexColor(i);
  241.  
  242.     // Scale vertex color
  243.     pv->color.Scale(color_scale);
  244.  
  245.     if (contrast_flag == TRUE)
  246.     {
  247.       // Perform contrast adjustment
  248.       pv->color.Scale(contrast);
  249.     }
  250.  
  251.     if (intensity_flag == TRUE)
  252.     {
  253.       // Perform intensity adjustment
  254.       pv->color.Add(intensity_adj);
  255.  
  256.       // Ensure color band values are positive
  257.       pv->color.Limit();
  258.     }
  259.  
  260.     // Clip vertex color to unity
  261.     if ((emax = pv->color.GetMaxColor()) > 1.0)
  262.       pv->color.Scale(1.0 / emax);
  263.   }
  264. }
  265.  
  266. void PolyRender::ScanEdges()    // Scan-convert edges
  267. {
  268.   int i;                // Loop index
  269.   VertexInfo *psv;      // Start vertex info pointer
  270.   VertexInfo *pev;      // End vertex info pointer
  271.   VertexInfo *psw;      // Swap vertex info pointer
  272.  
  273.   // Initialize edge list
  274.   for (i = ymin; i < ymax; i++)
  275.     edge_list[i].first = FALSE;
  276.  
  277.   for (i = 0; i < num_vert; i++)
  278.   {
  279.     // Get edge vertex pointers
  280.     psv = &(v_info[i]);
  281.     pev = &(v_info[(i + 1) % num_vert]);
  282.  
  283.     if (psv->screen.y > pev->screen.y)
  284.     {
  285.       // Swap edge vertex pointers
  286.       psw = psv; psv = pev; pev = psw;
  287.     }
  288.  
  289.     EdgeSetup(psv, pev);    // Initialize edge-scan DDA
  290.     EdgeScan(psv, pev);     // Scan-convert edge
  291.   }
  292. }
  293.  
  294. void PolyRender::DrawEdgeList()         // Draw edge list
  295. {
  296.   int y;                // Loop indices
  297.   EdgeInfo *pedge;      // Edge info pointer
  298.   ScanInfo *pss;        // Scan line start info pointer
  299.   ScanInfo *pes;        // Scan line end info pointer
  300.   ScanInfo *psw;        // Swap scan line info pointer
  301.  
  302.   pedge = &(edge_list[ymin]);
  303.   for (y = ymin; y < ymax; y++)
  304.   {
  305.     // Get scan line info pointers
  306.     pss = &(pedge->isect[0]);
  307.     pes = &(pedge->isect[1]);
  308.  
  309.     if (pss->x > pes->x)
  310.     {
  311.       // Swap scan line info pointers
  312.       psw = pss; pss = pes; pes = psw;
  313.     }
  314.  
  315.     // Ignore zero-length segments
  316.     if ((pss->x  / ss_rate) < (pes->x / ss_rate))
  317.     {
  318.       SpanSetup(pss, pes);      // Initialize span-scan DDA
  319.       SpanScan(pss, pes, y);    // Scan-convert span
  320.     }
  321.     pedge++;    // Point to next edge list element
  322.   }
  323. }
  324.  
  325. // Set up for edge scan
  326. void PolyRender::EdgeSetup( VertexInfo *psv, VertexInfo
  327.     *pev )
  328. {
  329.   int dy;           // Edge y-axis distance
  330.   int ex, sx;       // Vertex x-axis co-ordinates
  331.   int ey, sy;       // Vertex y-axis co-ordinates
  332.   long ez, sz;      // Vertex z-axis co-ordinates
  333.   DDA_Info sf;
  334.   DDA_Info de;      // Edge distances
  335.   IntRGB ec;        // End vertex color
  336.   IntRGB sc;        // Start vertex color
  337.   IntRGB temp;      // Temporary variable
  338.  
  339.   // Check for vertical edge
  340.   if (psv->screen.y == pev->screen.y)
  341.     return;
  342.  
  343.   // Get edge y-axis co-ordinates
  344.   sy = psv->ss_screen.y;
  345.   ey = pev->ss_screen.y;
  346.  
  347.   // Get edge x-axis co-ordinates
  348.   sx = psv->ss_screen.x;
  349.   ex = pev->ss_screen.x;
  350.  
  351.   // Get edge z-axis co-ordinates
  352.   sz = ScaleZ(psv->posn.GetZ());
  353.   ez = ScaleZ(pev->posn.GetZ());
  354.  
  355.   // Get vertex colors
  356.   sc.SetColor(psv->color);
  357.   ec.SetColor(pev->color);
  358.  
  359.   dy = ey - sy;
  360.  
  361.   // Calculate edge distances
  362.   de.x = ex - sx;
  363.   de.z = ez - sz;
  364.   de.color = ec - sc;
  365.  
  366.   // Initialize edge values
  367.   pi.x = sx;
  368.   pi.z = sz;
  369.   pi.color = sc;
  370.  
  371.   // Calculate delta values
  372.   si.x = IntFloorDiv(de.x, dy);
  373.   si.z = LongFloorDiv(de.z, (long) dy);
  374.   si.color.SetRed(IntFloorDiv(de.color.GetRed(), dy));
  375.   si.color.SetGreen(IntFloorDiv(de.color.GetGreen(), dy));
  376.   si.color.SetBlue(IntFloorDiv(de.color.GetBlue(), dy));
  377.  
  378.   sf.x = de.x - si.x * dy;
  379.   sf.z = de.z - si.z * (long) dy;
  380.   temp = si.color * dy;
  381.   sf.color = de.color - temp;
  382.  
  383.   r.x = sf.x * 2 - dy;
  384.   r.z = sf.z * 2L - (long) dy;
  385.   temp = sf.color * 2;
  386.   r.color = temp - dy;
  387.  
  388.   // Calculate increment values
  389.   inc.x = sf.x;
  390.   inc.z = sf.z;
  391.   inc.color = sf.color;
  392.  
  393.   // Calculate decrement values
  394.   dec.x = sf.x - dy;
  395.   dec.z = sf.z - (long) dy;
  396.   dec.color = sf.color - dy;
  397. }
  398.  
  399. // Scan-convert edge
  400. void PolyRender::EdgeScan( VertexInfo *psv, VertexInfo
  401.     *pev )
  402. {
  403.   int sy;               // Edge index
  404.   EdgeInfo *pedge;      // Edge info pointer
  405.   ScanInfo *pscan;      // Scan line info pointer
  406.  
  407.   // Initialize edge info pointer
  408.   pedge = &(edge_list[psv->screen.y]);
  409.  
  410.   // Scan-convert edge
  411.   for (sy = psv->ss_screen.y; sy < pev->ss_screen.y; sy++)
  412.   {
  413.     if ((sy % ss_rate) == 0)    // Edge info element ?
  414.     {
  415.       // Determine intersection info element
  416.       if (pedge->first == FALSE)
  417.       {
  418.         pscan = &(pedge->isect[0]);
  419.         pedge->first = TRUE;
  420.       }
  421.       else
  422.         pscan = &(pedge->isect[1]);
  423.  
  424.       // Insert edge intersection info
  425.       pscan->x = pi.x;
  426.       pscan->z = pi.z;
  427.       pscan->color = pi.color;
  428.  
  429.  
  430.  
  431.       pedge++;  // Point to next edge list element
  432.     }
  433.  
  434.     if (r.x >= 0)       // Update x-axis parameters
  435.     {
  436.       pi.x += si.x + 1;
  437.       r.x += dec.x;
  438.     }
  439.     else
  440.     {
  441.       pi.x += si.x;
  442.       r.x += inc.x;
  443.     }
  444.  
  445.     if (r.z >= 0L)      // Update z-axis parameters
  446.     {
  447.       pi.z += si.z + 1L;
  448.       r.z += dec.z;
  449.     }
  450.     else
  451.     {
  452.       pi.z += si.z;
  453.       r.z += inc.z;
  454.     }
  455.  
  456.     // Update red parameters
  457.     if (r.color.GetRed() >= 0)
  458.     {
  459.       pi.color.AddRed(si.color.GetRed() + 1);
  460.       r.color.AddRed(dec.color.GetRed());
  461.     }
  462.     else
  463.     {
  464.       pi.color.AddRed(si.color.GetRed());
  465.       r.color.AddRed(inc.color.GetRed());
  466.     }
  467.  
  468.     // Update green parameters
  469.     if (r.color.GetGreen() >= 0)
  470.     {
  471.       pi.color.AddGreen(si.color.GetGreen() + 1);
  472.       r.color.AddGreen(dec.color.GetGreen());
  473.     }
  474.     else
  475.     {
  476.       pi.color.AddGreen(si.color.GetGreen());
  477.       r.color.AddGreen(inc.color.GetGreen());
  478.     }
  479.  
  480.     // Update blue parameters
  481.     if (r.color.GetBlue() >= 0)
  482.     {
  483.       pi.color.AddBlue(si.color.GetBlue() + 1);
  484.       r.color.AddBlue(dec.color.GetBlue());
  485.     }
  486.     else
  487.     {
  488.       pi.color.AddBlue(si.color.GetBlue());
  489.       r.color.AddBlue(inc.color.GetBlue());
  490.     }
  491.   }
  492. }
  493.  
  494. // Set up for span scan (assumes non-zero span length)
  495. void PolyRender::SpanSetup( ScanInfo *pss, ScanInfo *pes )
  496. {
  497.   int dx;       // x-axis distance
  498.   DDA_Info sf;
  499.   DDA_Info de;  // Edge distances
  500.   IntRGB temp;  // Temporary variable
  501.  
  502.   dx = pes->x - pss->x;
  503.  
  504.   // Calculate span distances
  505.   de.z = pes->z - pss->z;
  506.   de.color = pes->color - pss->color;
  507.  
  508.   // Initialize edge values
  509.   pi.z = pss->z;
  510.   pi.color = pss->color;
  511.  
  512.   // Calculate delta values
  513.   si.z = LongFloorDiv(de.z, (long) dx);
  514.   si.color.SetRed(IntFloorDiv(de.color.GetRed(), dx));
  515.   si.color.SetGreen(IntFloorDiv(de.color.GetGreen(), dx));
  516.   si.color.SetBlue(IntFloorDiv(de.color.GetBlue(), dx));
  517.  
  518.   sf.z = de.z - si.z * (long) dx;
  519.   temp = si.color * dx;
  520.   sf.color = de.color - temp;
  521.  
  522.   r.z = sf.z * 2L - (long) dx;
  523.   temp = sf.color * 2;
  524.   r.color = temp - dx;
  525.  
  526.   // Calculate increment values
  527.   inc.z = sf.z;
  528.   inc.color = sf.color;
  529.  
  530.   // Calculate decrement values
  531.   dec.z = sf.z - (long) dx;
  532.   dec.color = sf.color - dx;
  533. }
  534.  
  535. // Scan-convert span
  536. void PolyRender::SpanScan( ScanInfo *pss, ScanInfo *pes,
  537.     int y )
  538. {
  539.   int ss_x;         // Supersampling pixel index
  540.   int first_x;      // First pixel index
  541.   long *pzb;        // Z-buffer entry pointer
  542.   ColorRGB rgb;     // RGB color
  543.  
  544.   // Calculate first pixel index
  545.   first_x = (pss->x + ss_rate - 1) / ss_rate;
  546.  
  547.   // Initialize Z-buffer entry pointer
  548.   pzb = &(z_buffer[y][first_x]);
  549.  
  550.   // Initialize bitmap pixel pointer
  551.   pbmap->SetPixelPtr(first_x, y);
  552.  
  553.   // Scan-convert span
  554.   for (ss_x = pss->x; ss_x < pes->x; ss_x++)
  555.   {
  556.     if ((ss_x % ss_rate) == 0)  // Bitmap pixel ?
  557.     {
  558.       if (pi.z < *pzb)  // Check pixel visibility
  559.       {
  560.         *pzb = pi.z;            // Update Z-buffer entry
  561.  
  562.         pi.color.SetColorRGB(&rgb); // Get current RGB color
  563.  
  564.         pbmap->SetCurrPixel(rgb);   // Set bitmap pixel
  565.  
  566.       }
  567.  
  568.       pzb++;    // Increment Z-buffer entry pointer
  569.  
  570.       pbmap->IncPixelPtr();     // Increment pixel pointer
  571.     }
  572.  
  573.     if (r.z >= 0L)          // Update z-axis parameters
  574.  
  575.     {
  576.       pi.z += si.z + 1L;
  577.       r.z += dec.z;
  578.     }
  579.     else
  580.     {
  581.       pi.z += si.z;
  582.       r.z += inc.z;
  583.     }
  584.  
  585.     // Update red parameters
  586.     if (r.color.GetRed() >= 0)
  587.     {
  588.       pi.color.AddRed(si.color.GetRed() + 1);
  589.       r.color.AddRed(dec.color.GetRed());
  590.     }
  591.     else
  592.     {
  593.       pi.color.AddRed(si.color.GetRed());
  594.       r.color.AddRed(inc.color.GetRed());
  595.     }
  596.  
  597.     // Update green parameters
  598.     if (r.color.GetGreen() >= 0)
  599.     {
  600.       pi.color.AddGreen(si.color.GetGreen() + 1);
  601.       r.color.AddGreen(dec.color.GetGreen());
  602.     }
  603.     else
  604.     {
  605.       pi.color.AddGreen(si.color.GetGreen());
  606.       r.color.AddGreen(inc.color.GetGreen());
  607.     }
  608.  
  609.     // Update blue parameters
  610.     if (r.color.GetBlue() >= 0)
  611.     {
  612.       pi.color.AddBlue(si.color.GetBlue() + 1);
  613.       r.color.AddBlue(dec.color.GetBlue());
  614.     }
  615.     else
  616.     {
  617.       pi.color.AddBlue(si.color.GetBlue());
  618.       r.color.AddBlue(inc.color.GetBlue());
  619.     }
  620.   }
  621. }
  622.  
  623.